# encoding: utf-8
"""
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    created by lane.chang on '17/10/2024'
    comment: 流程节点
"""
from fastapi import APIRouter, Request, Body, Query

from config import Config
from project.core.exception import NoRecordError, BizError
from project.core.function import json_response
from project.lib.common import Global
from project.lib.decorator import api_common, exec_duration
from project.lib.constant import DEFAULT_VALUE
from project.service.node import NodeService
from project.model.basic import BusinessType, PhoneType, InvoiceType, SelectMode, TimeSet, TimeMode, MealPeriod
from project.model.database.flow import Flow
from project.model.database.node import Node


node_router = APIRouter(prefix='/m', tags=['manager.node'])


@node_router.post('/node/add', summary='新增节点')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), verify_login=True)
@exec_duration(add_return=True)
async def do_node_add(request: Request,
                      flow_id: int = Body(..., title='服务流程id'),
                      last_node_id: int = Body(0, title='上一节点id'),
                      name: str = Body('', max_length=30, title='节点名称'),
                      node_type: str = Body('', max_length=30, title='节点类型'),
                      title: str = Body('', max_length=200, title='标题'),
                      introduction: str = Body('', title='节点介绍'),
                      business_type: BusinessType.enums(fixed=Global.count(), with_blank=True) = Body('', title='业务类型', description='catering(餐饮)/shopping(购物)/other(其它)'),
                      button_text: str = Body('', title='按钮文本'),
                      display_text: str = Body('', title='文本展示'),
                      phone_type: PhoneType.enums(fixed=Global.count(), with_blank=True) = Body('', title='手机号类型', description='eleven_bit(11位)/last_four_bit(后四位)'),
                      title_icon: str = Body('', title='内容图标'),
                      invoice_types: list[InvoiceType.enums(fixed=Global.count())] = Body([], title='发票类型列表', description='electronic(电子发票)/paper(纸质发票)'),
                      select_mode: SelectMode.enums(fixed=Global.count()) = Body('single', title='选择方式', description='single(单选)/multiple(多选)'),
                      is_group: int = Body(0, title='是否需要分组', description='0: 需要 1:不需要'),
                      timeset: TimeSet = Body('', title='时间设置', description='{"dates": ["today", "tomorrow", "after_tomorrow"], "meal_period": {"start_time": xxx, "end_time": xxx}, "interval": 60(单位分钟)}'),
                      is_send_sms: int = Body(0, title='是否发送短信', description='0: 不发送 1: 发送'),
                      sms_greet: str = Body('', title='短信问候', max_length=30),
                      is_display_reducible: int = Body(0, title='是否展示可约量', description='0:否 1:是'),
                      is_display_calendar: int = Body(0, title='是否展示可约量', description='0:否 1:是'),
                      time_mode: TimeMode.enums(fixed=Global.count(), with_blank=True) = Body('', title='时间设置', description='period(时间段)/point(时间点)'),
                      time_periods: list[MealPeriod] = Body([], title='时间段列表'),
                      time_interval: int = Body(0, title='时间间隔', description='单位: 分钟'),
                      time_durations: list[str] = Body('', title='时长设置'),
                      session=None,
                      body_params=None):
    """
    **desc**: 新增流程节点

    **url**: http(s)://{0}.udicaria.com/m/node/add

    **method**: POST

    **params**:

        <body>:
            flow_id: 服务流程id
            last_node_id: 上一节点id(如果没有则不传)
            name: 节点名称
            node_type: 节点类型
            title: 标题
            introduction: 节点介绍
            business_type: 业务类型 catering(餐饮)/shopping(购物)/other(其它)
            button_text: 按钮文本
            display_text: 文本展示
            phone_type: 手机号类型 eleven_bit(11位)/last_four_bit(后四位)
            title_icon: 内容图标
            invoice_types: []发票类型列表 electronic(电子发票)/paper(纸质发票)
            select_mode: 选择方式 single(单选)/multiple(多选)
            is_group: 是否分组 0: 需要 1:不需要
            timeset: 时间段设置 {"dates": ["today", "tomorrow", "after_tomorrow"], "meal_period": {"start_time": xxx, "end_time": xxx}, "interval": 60(单位分钟)}
            is_send_sms: 是否发送短信 0: 不发送 1: 发送
            sms_greet: 短信问候语
            is_display_reducible: 是否展示可约量 0:否 1:是
            is_display_calendar: 是否展示可约量 0:否 1:是
            time_mode: 时间设置
            time_periods: 时间段列表
            time_interval: 时间间隔
            time_durations: 时长列表

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    node = await NodeService.do_node_add(session, body_params)

    return json_response(data=node.dict('id', 'code') if node else {})


@node_router.post('/node/update', summary='修改节点')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), verify_login=True)
@exec_duration(add_return=True)
async def do_node_update(request: Request,
                         id: int = Body(..., title='流程节点id'),
                         name: str = Body(DEFAULT_VALUE, max_length=30, title='节点名称'),
                         node_type: str = Body(DEFAULT_VALUE, max_length=30, title='节点类型'),
                         title: str = Body(DEFAULT_VALUE, max_length=200, title='标题'),
                         introduction: str = Body(DEFAULT_VALUE, title='节点介绍'),
                         business_type: BusinessType.enums(fixed=Global.count(), with_blank=True) = Body(DEFAULT_VALUE, title='业务类型', description='catering(餐饮)/shopping(购物)/other(其它)'),
                         button_text: str = Body(DEFAULT_VALUE, title='按钮文本'),
                         display_text: str = Body(DEFAULT_VALUE, title='文本展示'),
                         phone_type: PhoneType.enums(fixed=Global.count(), with_blank=True) = Body(DEFAULT_VALUE, title='手机号类型', description='eleven_bit(11位)/last_four_bit(后四位)'),
                         title_icon: str = Body(DEFAULT_VALUE, title='内容图标'),
                         invoice_types: list[InvoiceType.enums(fixed=Global.count())] = Body(DEFAULT_VALUE, title='发票类型列表', description='electronic(电子发票)/paper(纸质发票)'),
                         select_mode: SelectMode.enums(fixed=Global.count()) = Body(DEFAULT_VALUE, title='选择方式', description='single(单选)/multiple(多选)'),
                         is_group: int = Body(DEFAULT_VALUE, title='是否需要分组', description='0: 需要 1:不需要'),
                         timeset: TimeSet = Body(DEFAULT_VALUE, title='时间设置', description='{"dates": ["today", "tomorrow", "after_tomorrow"], "meal_period": {"start_time": xxx, "end_time": xxx}, "interval": 60(单位分钟)}'),
                         is_send_sms: int = Body(DEFAULT_VALUE, title='是否发送短信', description='0: 不发送 1: 发送'),
                         sms_greet: str = Body(DEFAULT_VALUE, title='短信问候语', max_length=35),
                         is_display_reducible: int = Body(DEFAULT_VALUE, title='是否展示可约量', description='0:否 1:是'),
                         is_display_calendar: int = Body(DEFAULT_VALUE, title='是否展示可约量', description='0:否 1:是'),
                         time_mode: TimeMode.enums(fixed=Global.count(), with_blank=True) = Body(DEFAULT_VALUE, title='时间设置', description='period(时间段)/point(时间点)'),
                         time_periods: list[MealPeriod] = Body(DEFAULT_VALUE, title='时间段列表'),
                         time_interval: int = Body(DEFAULT_VALUE, title='时间间隔', description='单位: 分钟'),
                         time_durations: list[str] = Body(DEFAULT_VALUE, title='时长设置'),
                         custom_icon: str = Body(DEFAULT_VALUE, title='自定义图标base64编码'),
                         session=None,
                         body_params=None):
    """
    **desc**: 修改节点

    **url**: http(s)://{0}.udicaria.com/m/node/update

    **method**: POST

    **params**:

        <body>:
            id: 流程节点id
            name: 节点名称
            node_type: 节点类型
            title: 标题
            introduction: 节点介绍
            business_type: 业务类型 catering(餐饮)/shopping(购物)/other(其它)
            button_text: 按钮文本
            display_text: 文本展示
            phone_type: 手机号类型 eleven_bit(11位)/last_four_bit(后四位)
            title_icon: 内容图标
            invoice_types: []发票类型列表 electronic(电子发票)/paper(纸质发票)
            select_mode: 选择方式 single(单选)/multiple(多选)
            is_group: 是否分组 0: 需要 1:不需要
            timeset: 时间段设置 {"dates": ["today", "tomorrow", "after_tomorrow"], "meal_period": {"start_time": xxx, "end_time": xxx}, "interval": 60(单位分钟)}
            is_send_sms: 是否发送短信 0: 不发送 1: 发送
            sms_greet: 短信问候语
            is_display_reducible: 是否展示可约量 0:否 1:是
            is_display_calendar: 是否展示可约量 0:否 1:是
            time_mode: 时间设置
            time_periods: 时间段列表
            time_interval: 时间间隔
            time_durations: 时长列表

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    try:
        await NodeService.do_node_update(session, id, body_params)
    except NoRecordError:
        raise BizError('节点不存在')

    return json_response()


@node_router.get('/node/list', summary='节点列表')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), verify_login=True)
@exec_duration(add_return=True)
async def get_node_list(request: Request, flow_id: int = Query(..., title='服务流程id'), session=None):
    """
    **desc**: 节点列表

    **url**: http(s)://{0}.udicaria.com/m/node/list

    **method**: GET

    **params**:

        <query>:
            flow_id: 服务流程id

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data: [
                {
                    code: 节点编号
                    name: 节点名称
                    node_type: 节点类型
                    title: 标题
                    introduction: 节点介绍
                    business_type: 业务类型
                    button_text: 按钮文本
                    display_text: 文本展示
                    timeset: 时间设置
                    phone_type: 手机类型
                    title_icon: 标题图标
                    invoice_types: 发票类型列表
                }
            ]
            exec_time: 接口后端处理时长
        }
    """
    flow = await Flow.fetch_one(session, wheres=(Flow.id == flow_id))
    if not flow:
        return json_response()

    nodes = await Node.fetch_all(session, wheres=(Node.flow_id == flow_id, ~Node.is_deleted))
    nodes = NodeService.sorted_nodes(nodes)

    return json_response(data=[v.dict() for v in nodes])


@node_router.get('/node/detail', summary='节点详情')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), verify_login=True)
@exec_duration(add_return=True)
async def get_node_detail(request: Request, id: int = Query(..., title='流程节点id'), session=None):
    """
    **desc**: 节点列表

    **url**: http(s)://{0}.udicaria.com/m/node/detail

    **method**: GET

    **params**:

        <query>:
            id: 流程节点id

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data: {
                code: 节点编号
                name: 节点名称
                node_type: 节点类型
                title: 标题
                introduction: 节点介绍
                business_type: 业务类型
                button_text: 按钮文本
                display_text: 文本展示
                timeset: 时间设置
                phone_type: 手机类型
                title_icon: 标题图标
                invoice_types: 发票类型列表
                select_mode: 选择方式 single(单选)/multiple(多选)
                is_group: 是否分组 0: 需要 1:不需要
                timeset: 时间段设置 {"dates": ["today", "tomorrow", "after_tomorrow"], "meal_period": {"start_time": xxx, "end_time": xxx}, "interval": 60(单位分钟)}
                is_send_sms: 是否发送短信 0: 不发送 1: 发送
                sms_greet: 短信问候语
                is_display_reducible: 是否展示可约量 0:否 1:是
                is_display_calendar: 是否展示可约量 0:否 1:是
                time_mode: 时间设置
                time_periods: 时间段列表
                time_interval: 时间间隔
                time_durations: 时长列表
            }
            exec_time: 接口后端处理时长
        }
    """
    node = await Node.fetch_one(session, wheres=(Node.id == id))

    return json_response(data=node.dict() if node else {})


@node_router.post('/node/delete', summary='删除节点')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), verify_login=True)
@exec_duration(add_return=True)
async def do_node_delete(request: Request, id: int = Body(..., title='流程节点id', embed=True), session=None):
    """
    **desc**: 删除节点

    **url**: http(s)://{0}.udicaria.com/m/node/delete

    **method**: POST

    **params**:

        <body>:
            id: 流程节点id

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    await NodeService.do_node_delete(session, node_id=id)

    return json_response()
